﻿using Mapster;
using Model.Entites.Base;
using SqlSugar;
using System.Linq.Expressions;

namespace Utils.Extensions
{
    public class DbCachExtensions<T> where T : ModelBase, new()
    {
        private readonly ISqlSugarClient _db;
        private readonly string _cacheKeyPrefix;
        private readonly CacheKeyManager<T> _cacheKeyManager;

        public DbCachExtensions(ISqlSugarClient Db)
        {
            _db = Db;
            _cacheKeyPrefix = typeof(T).Name + "_";
            _cacheKeyManager = new CacheKeyManager<T>();
        }

        #region 新增

        /// <summary>
        /// 批量添加实体(s List)
        /// </summary>
        /// <param name="entities">要添加的实体列表</param>
        /// <returns>受影响的行数</returns>
        public async Task<int> AddCache(List<T> entities)
        {
            var result = await _db.Add(entities);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 添加单个实体
        /// </summary>
        /// <param name="entity">要添加的实体</param>
        /// <returns>受影响的行数</returns>
        public async Task<int> AddCache(T entity)
        {
            var result = await _db.Add(entity);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 添加实体并返回新增的实体对象
        /// </summary>
        /// <param name="entity">要添加的实体</param>
        /// <returns>新增的实体对象</returns>
        public async Task<T> AddCacheREntity(T entity)
        {
            var result = await _db.AddREntity(entity);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 添加实体并返回自增ID
        /// </summary>
        /// <param name="entity">要添加的实体</param>
        /// <returns>自增ID</returns>
        public async Task<int> AddCacheRId(T entity)
        {
            var result = await _db.AddRId(entity);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        #endregion 新增

        #region 删除

        /// <summary>
        /// 根据ID删除实体
        /// </summary>
        /// <param name="id">实体的ID</param>
        /// <returns>如果删除成功返回true，否则返回false</returns>
        public async Task<bool> DeleteCache(int id)
        {
            var result = await _db.Delete<T>(id);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 根据ID列表删除实体
        /// </summary>
        /// <param name="ids">实体的ID列表</param>
        /// <returns>如果删除成功返回true，否则返回false</returns>
        public async Task<bool> DeleteCache(List<int> ids)
        {
            var result = await _db.Delete<T>(ids);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 根据条件表达式删除实体
        /// </summary>
        /// <param name="whereExpression">删除条件表达式</param>
        /// <returns>如果删除成功返回true，否则返回false</returns>
        public async Task<bool> DeleteCache(Expression<Func<T, bool>> whereExpression)
        {
            var result = await _db.Delete(whereExpression);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        #endregion 删除

        #region 查询

        /// <summary>
        /// 根据ID获取单个实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Db"></param>
        /// <param name="id"></param>
        /// <param name="isCache"></param>
        /// <param name="cacheSecond"></param>
        /// <returns></returns>
        public async Task<T> GetCache(int id, bool isCache = true, int cacheSecond = 120)
        {
            T retsult = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:GetCach_{id}";
                retsult = CacheHelper.GetCache(_cachekey) as T;
                if (retsult == null)
                {
                    retsult = await _db.Get<T>(id);
                    CacheHelper.SetCache(_cachekey, retsult, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }
            return retsult ?? await _db.Get<T>(id); 
        }

        /// <summary>
        /// 根据条件表达式获取单个实体
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public async Task<T> GetCache(Expression<Func<T, bool>> whereExpression = null, bool isCache = true, int cacheSecond = 120)
        {
            var condition = _db.Queryable<T>().Where(u => !u.IsDeleted).WhereIF(whereExpression != null, whereExpression);

            T retsult = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:GetCach_{condition}";
                retsult = CacheHelper.GetCache(_cachekey) as T;
                if (retsult == null)
                {
                    retsult = await TryExtensions.Trycatch(() => condition.FirstAsync());
                    CacheHelper.SetCache(_cachekey, retsult, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }
            return retsult ?? await TryExtensions.Trycatch(() => condition.FirstAsync());
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public async Task<int> CountCache(Expression<Func<T, bool>> whereExpression = null, bool isCache = true, int cacheSecond = 120)
        {
            var result = 0;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:CountCach_{whereExpression}";
                result = CacheHelper.GetCache(_cachekey) as int? ?? 0;
                if (result == 0)
                {
                    result = await TryExtensions.Trycatch(() =>
                    _db.Queryable<T>()
                    .Where(u => !u.IsDeleted)
                    .WhereIF(whereExpression != null, whereExpression)
                    .CountAsync());
                    CacheHelper.SetCache(_cachekey, result, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }

            return result;
        }

        /// <summary>
        /// 根据条件表达式获取实体列表
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public async Task<List<T>> GetCacheList(Expression<Func<T, bool>> whereExpression = null, bool isCache = true, int cacheSecond = 120)
        {
            var condition = _db.Queryable<T>().Where(u => !u.IsDeleted).WhereIF(whereExpression != null, whereExpression);

            List<T> retsult = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:GetCachList_{condition}";
                retsult = CacheHelper.GetCache(_cachekey) as List<T>;
                if (retsult == null)
                {
                    retsult = await TryExtensions.Trycatch(() => condition.ToListAsync());
                    CacheHelper.SetCache(_cachekey, retsult, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }
            return retsult ?? await TryExtensions.Trycatch(() => condition.ToListAsync());
        }

        /// <summary>
        /// 根据SQL语句获取实体列表
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public async Task<List<T>> GetCacheList(string sql, bool isCache = true, int cacheSecond = 120)
        {
            List<T> retsult = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:GetCachList_{sql}";
                retsult = CacheHelper.GetCache(_cachekey) as List<T>;
                if (retsult == null)
                {
                    retsult = await TryExtensions.Trycatch(() => _db.SqlQueryable<T>(sql).ToListAsync());
                    CacheHelper.SetCache(_cachekey, retsult, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }
            return retsult ?? await TryExtensions.Trycatch(() => _db.SqlQueryable<T>(sql).ToListAsync());
        }

        /// <summary>
        /// 是否存在这条记录
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public async Task<bool> AnyCache(Expression<Func<T, bool>> whereExpression = null, bool isCache = true, int cacheSecond = 120)
        {
            var result = false;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:AnyCach_{whereExpression}";
                result = CacheHelper.GetCache(_cachekey) as bool? ?? false;
                if (result == false)
                {
                    result = await TryExtensions.Trycatch(() =>
                    _db.Queryable<T>()
                    .Where(u => !u.IsDeleted)
                    .WhereIF(whereExpression != null, whereExpression)
                    .AnyAsync());
                    CacheHelper.SetCache(_cachekey, result, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }

            return result;
        }

        /// <summary>
        /// 根据ID判断记录是否存在
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<bool> AnyCache(int id)
        {
            return await AnyCache(u => u.Id == id);
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderBy"></param>
        /// <param name="orderByType"></param>
        /// <returns></returns>
        public async Task<(List<T>, int, int)> PageCache(Expression<Func<T, bool>> expression = null, int pageIndex = 1, int pageSize = 15,
            Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc, bool isCache = true, int cacheSecond = 120)
        {
            RefAsync<int> totalCount = 0;

            var condition = _db.Queryable<T>()
            .Where(u => !u.IsDeleted)
            .WhereIF(expression != null, expression)
            .OrderByIF(orderBy != null, orderBy, orderByType);

            List<T> list = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:Page_{condition}_{pageIndex}_{pageSize}_{orderByType}";
                list = CacheHelper.GetCache(_cachekey) as List<T>;
                if (list == null)
                {
                    list = await TryExtensions.Trycatch(() => condition.ToPageListAsync(pageIndex, pageSize, totalCount));
                    CacheHelper.SetCache(_cachekey, list, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }

            list ??= await TryExtensions.Trycatch(() => condition.ToPageListAsync(pageIndex, pageSize, totalCount.Value));
            int pageCount = Math.Ceiling(totalCount.Value.ToDecimal() / pageSize.ToDecimal()).ToInt();
            return (list, totalCount.Value, pageCount);
        }

        /// <summary>
        /// 根据SQL分页查询
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderBy"></param>
        /// <param name="orderByType"></param>
        /// <returns></returns>
        public async Task<(List<T>, int, int)> PageCache(string sql = null, int pageIndex = 1, int pageSize = 15,
            Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc, bool isCache = true, int cacheSecond = 120)
        {
            RefAsync<int> totalCount = 0;

            var condition = _db.SqlQueryable<T>(sql).OrderByIF(orderBy != null, orderBy, orderByType);

            List<T> list = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:Page_{condition}_{pageIndex}_{pageSize}_{orderByType}";
                list = CacheHelper.GetCache(_cachekey) as List<T>;
                if (list == null)
                {
                    list = await TryExtensions.Trycatch(() => condition.ToPageListAsync(pageIndex, pageSize, totalCount));
                    CacheHelper.SetCache(_cachekey, list, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }

            list ??= await TryExtensions.Trycatch(() => condition.ToPageListAsync(pageIndex, pageSize, totalCount.Value));
            int pageCount = Math.Ceiling(totalCount.Value.ToDecimal() / pageSize.ToDecimal()).ToInt();
            return (list, totalCount.Value, pageCount);
        }

        #endregion 查询

        #region 查询2

        /// <summary>
        /// 根据ID获取单个实体
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<V> GetCache<V>(int id, bool isCache = true, int cacheSecond = 120)
        {
            var _cachekey = $"{_cacheKeyPrefix}:GetCach_{id}/{typeof(V).Name}";
            V retsult = default;
            if (isCache)
            {
                retsult = CacheHelper.GetCache(_cachekey).Adapt<V>();
                if (retsult == null)
                {
                    retsult = await TryExtensions.Trycatch(() => _db.Queryable<T>().Where(u => !u.IsDeleted).Select<V>().InSingleAsync(id));
                    CacheHelper.SetCache(_cachekey, retsult, cacheSecond);
                }
            }
            return retsult ?? await TryExtensions.Trycatch(() => _db.Queryable<T>().Where(u => !u.IsDeleted).Select<V>().InSingleAsync(id));
        }

        /// <summary>
        /// 根据条件表达式获取单个实体
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public async Task<V> GetCache<V>(Expression<Func<T, bool>> whereExpression = null, bool isCache = true, int cacheSecond = 120)
        {
            var condition = _db.Queryable<T>().Where(u => !u.IsDeleted).WhereIF(whereExpression != null, whereExpression).Select<V>();

            V retsult = default;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:GetCach_{condition}/{typeof(V).Name}";
                retsult = CacheHelper.GetCache(_cachekey).Adapt<V>();
                if (retsult == null)
                {
                    retsult = await TryExtensions.Trycatch(() => condition.FirstAsync());
                    CacheHelper.SetCache(_cachekey, retsult, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }
            return retsult ?? await TryExtensions.Trycatch(() => condition.FirstAsync());
        }

        /// <summary>
        /// 根据条件表达式获取实体列表
        /// </summary>
        /// <param name="whereExpression"></param>
        /// <returns></returns>
        public async Task<List<V>> GetCacheList<V>(Expression<Func<T, bool>> whereExpression = null, bool isCache = true, int cacheSecond = 120)
        {
            var condition = _db.Queryable<T>().Where(u => !u.IsDeleted).WhereIF(whereExpression != null, whereExpression).Select<V>();

            List<V> retsult = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:GetCachList_{condition}/{typeof(V).Name}";
                retsult = CacheHelper.GetCache(_cachekey) as List<V>;
                if (retsult == null)
                {
                    retsult = await TryExtensions.Trycatch(() => condition.ToListAsync());
                    CacheHelper.SetCache(_cachekey, retsult, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }
            return retsult ?? await TryExtensions.Trycatch(() => condition.ToListAsync());
        }

        /// <summary>
        /// 根据SQL语句获取实体列表
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public async Task<List<V>> GetCacheList<V>(string sql, bool isCache = true, int cacheSecond = 120)
        {
            List<V> retsult = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:GetCachList_{sql}/{typeof(V).Name}";
                retsult = CacheHelper.GetCache(_cachekey) as List<V>;
                if (retsult == null)
                {
                    retsult = await TryExtensions.Trycatch(() => _db.SqlQueryable<T>(sql).Select<V>().ToListAsync());
                    CacheHelper.SetCache(_cachekey, retsult, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }
            return retsult ?? await TryExtensions.Trycatch(() => _db.SqlQueryable<T>(sql).Select<V>().ToListAsync());
        }

        /// <summary>
        /// 分页查询
        /// </summary>
        /// <param name="expression"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderBy"></param>
        /// <param name="orderByType"></param>
        /// <returns></returns>
        public async Task<(List<V>, int, int)> PageCache<V>(Expression<Func<T, bool>> expression = null, int pageIndex = 1, int pageSize = 15,
            Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc, bool isCache = true, int cacheSecond = 120)
        {
            RefAsync<int> totalCount = 0;

            var condition = _db.Queryable<T>()
            .Where(u => !u.IsDeleted)
            .WhereIF(expression != null, expression)
            .OrderByIF(orderBy != null, orderBy, orderByType)
            .Select<V>();

            List<V> list = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:Page_{condition}_{pageIndex}_{pageSize}_{orderByType}/{typeof(V).Name}";
                list = CacheHelper.GetCache(_cachekey) as List<V>;
                if (list == null)
                {
                    list = await TryExtensions.Trycatch(() => condition.ToPageListAsync(pageIndex, pageSize, totalCount));
                    CacheHelper.SetCache(_cachekey, list, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }

            list ??= await TryExtensions.Trycatch(() => condition.ToPageListAsync(pageIndex, pageSize, totalCount.Value));
            int pageCount = Math.Ceiling(totalCount.Value.ToDecimal() / pageSize.ToDecimal()).ToInt();
            return (list, totalCount.Value, pageCount);
        }

        /// <summary>
        /// 根据SQL分页查询
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <param name="orderBy"></param>
        /// <param name="orderByType"></param>
        /// <returns></returns>
        public async Task<(List<V>, int, int)> PageCache<V>(string sql = null, int pageIndex = 1, int pageSize = 15,
            Expression<Func<T, object>> orderBy = null, OrderByType orderByType = OrderByType.Asc, bool isCache = true, int cacheSecond = 120)
        {
            RefAsync<int> totalCount = 0;

            var condition = _db.SqlQueryable<T>(sql).OrderByIF(orderBy != null, orderBy, orderByType).Select<V>();

            List<V> list = null;
            if (isCache)
            {
                var _cachekey = $"{_cacheKeyPrefix}:Page_{condition}_{pageIndex}_{pageSize}_{orderByType}/{typeof(V).Name}";
                list = CacheHelper.GetCache(_cachekey) as List<V>;
                if (list == null)
                {
                    list = await TryExtensions.Trycatch(() => condition.ToPageListAsync(pageIndex, pageSize, totalCount));
                    CacheHelper.SetCache(_cachekey, list, cacheSecond);
                    _cacheKeyManager.AddCacheKey(_cachekey);
                }
            }

            list ??= await TryExtensions.Trycatch(() => condition.ToPageListAsync(pageIndex, pageSize, totalCount.Value));
            int pageCount = Math.Ceiling(totalCount.Value.ToDecimal() / pageSize.ToDecimal()).ToInt();
            return (list, totalCount.Value, pageCount);
        }

        #endregion 查询2

        #region 更新

        /// <summary>
        /// 更新实体
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<int> UpdateCache(T entity)
        {
            var result = await _db.Update(entity);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 只更新不为null的字段
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        public async Task<int> UpdateCahceNotNull(T entity)
        {
            var result = await _db.UpdateNotNull(entity);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 更新实体并指定更新与忽略的列
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="columns"></param>
        /// <param name="igcolumns"></param>
        /// <returns></returns>
        public async Task<int> UpdateCache(T entity, Expression<Func<T, object>> columns = null, Expression<Func<T, object>> igcolumns = null)
        {
            var result = await _db.Update(entity, columns, igcolumns);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 更新实体并指定更新与忽略的列
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="columns"></param>
        /// <param name="igcolumns"></param>
        /// <returns></returns>
        public async Task<int> UpdateCache(Expression<Func<T, bool>> expression = null, Expression<Func<T, T>> columns = null, Expression<Func<T, object>> igcolumns = null)
        {
            var result = await _db.Update(expression, columns, igcolumns);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        /// <summary>
        /// 更新实体并指定更新与忽略的列
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="id"></param>
        /// <param name="columns"></param>
        /// <param name="igcolumns"></param>
        /// <returns></returns>
        public async Task<int> UpdateCache(int id, Expression<Func<T, T>> columns = null, Expression<Func<T, object>> igcolumns = null)
        {
            return await UpdateCache(u => u.Id == id, columns, igcolumns);
        }

        /// <summary>
        /// 批量更新实体并指定更新与忽略的列
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="columns"></param>
        /// <param name="igcolumns"></param>
        /// <returns></returns>
        public async Task<int> UpdateCache(List<T> entity, Expression<Func<T, object>> columns = null, Expression<Func<T, object>> igcolumns = null)
        {
            var result = await _db.Update(entity, columns, igcolumns);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        #endregion 更新

        #region 软删除

        /// <summary>
        /// 软删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Db"></param>
        /// <param name="id"></param>
        /// <param name="DeleterId"></param>
        /// <returns></returns>
        public async Task<int> SoftDeleteCache(int id, int DeleterId = 0)
        {
            return await SoftDeleteCache(u => u.Id == id, DeleterId);
        }

        /// <summary>
        /// 软删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Db"></param>
        /// <param name="ids"></param>
        /// <param name="DeleterId"></param>
        /// <returns></returns>
        public async Task<int> SoftDeleteCache(List<int> ids, int DeleterId = 0)
        {
            return await SoftDeleteCache(u => ids.Contains(u.Id), DeleterId);
        }

        /// <summary>
        /// 软删除
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="Db"></param>
        /// <param name="wherexp"></param>
        /// <param name="DeleterId"></param>
        /// <returns></returns>
        public async Task<int> SoftDeleteCache(Expression<Func<T, bool>> wherexp, int DeleterId = 0)
        {
            var result = await _db.SoftDelete(wherexp, DeleterId);
            _cacheKeyManager.ClearAllRelatedCacheKeys();
            return result;
        }

        #endregion 软删除
    }
}